// 在仅包含 0 和 1 的数组 A 中，一次 K 位翻转包括选择一个长度为 K 的（连续）子数组，
// 同时将子数组中的每个 0 更改为 1，而每个 1 更改为 0。

// 返回所需的 K 位翻转的最小次数，以便数组没有值为 0 的元素。如果不可能，返回 -1。

const minKBitFlips = function (A: number[], K: number): number {
    let left = 0;// 左指针
    let count = 0;
    const queue: number[] = [];// 队列：哪些元素为首的子区间发生了翻转
    while (left < A.length) {// 存在边界条件
        // 当走出翻转区间时，第一个元素出队
        if (queue.length > 0 && left >= queue[0] + K) {
            queue.shift();
        }
        // 重要判断性质
        if (queue.length % 2 === A[left]) {
            // 边界情况，剩下的元素不够翻转了
            if (left + K > A.length) {
                return -1;
            }
            // 需要翻转的元素入队
            queue.push(left);
            count++;
        }
        left++;
    }
    return count;
};

minKBitFlips(
    [0, 0, 0, 1, 0, 1, 1, 0], 3)

// 这道题目整体上编码难度不大，但思考的过程比较不清晰，难度较大
// 题目大意需要每次翻转长度为 K 的子数组，求最少的翻转次数使数组中所有的 0 都更改为 1。如果不能实现，则返回 -1
// 首先这里有一个重要性质：当翻转次数对 2 取余时与当前元素判断可以判断是否需要翻转
// 这里需要想到利用队列模拟滑动窗口，该滑动窗口的含义是前面 K - 1个元素中，以哪些位置起始的子区间进行了翻转
// 这里可以得到两个性质：
// 1.队列内存在以哪些位置起始的子区间进行了翻转
// 2.队列长度代表了当前扫描位置的翻转次数
// 该滑动窗口从左向右滑动，如果当前位置 i 需要翻转，则把该位置存储到队列中。
// 因为我们需要把所有的 0 都翻转为 1 ，所以每次遇到需要翻转的 0 肯定是都需要进行入队操作的
// 这里还存在边界情况，当需要翻转大小为 K 的子区间，但是后面剩余的元素不到 K 个了，直接返回 -1
// 实际上每次扫描的过程中，我们只以滑动窗口的左边界进行判断

